package com.bd.wechat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bd.wechat.core.R;
import com.bd.wechat.entity.Store;
import com.bd.wechat.entity.request.NearestRequest;
import com.bd.wechat.entity.response.map.NearestOneStoreResponse;
import com.bd.wechat.mapper.StoreMapper;
import com.bd.wechat.service.StoreService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bd.wechat.utils.GeoUtils;
import com.bd.wechat.utils.Location;
import com.bd.wechat.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统维护的 服务实现类
 * </p>
 *
 * @author linhs
 * @since 2024-11-29
 */
@Service
@Slf4j
public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements StoreService {
    @Override
    public List<Store> getNearestStore(NearestRequest nearestRequest) {

        LambdaQueryWrapper<Store> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(nearestRequest.getProvince()), Store::getProvince, nearestRequest.getProvince());
        wrapper.eq(StringUtils.isNotEmpty(nearestRequest.getCity()), Store::getCity, nearestRequest.getCity());
        List<Store> storeList = this.list(wrapper);
        if (CollectionUtils.isEmpty(storeList)) {
            return new ArrayList<>();
        }

        if (nearestRequest.getCount() == null) {
            nearestRequest.setCount(5);
        }


        return  findNearestLocations(storeList, nearestRequest.getLat(), nearestRequest.getLon(),nearestRequest.getCount());

    }


    private static List<Store> findNearestLocations(List<Store> storeList, double targetLat, double targetLon,Integer count) {
        List<Store> nearestStoreList = new ArrayList<>();
        // 创建一个列表来保存每个位置的距离和索引
        List<LocationDistance> locationDistances = new ArrayList<>();

        for (int i = 0; i < storeList.size(); i++) {
            double distance = haversineDistance(targetLat, targetLon, storeList.get(i).getLat(), storeList.get(i).getLon());
            locationDistances.add(new LocationDistance(i, distance));
        }

        // 根据距离升序排序
        Collections.sort(locationDistances, Comparator.comparingDouble(LocationDistance::getDistance));

        // 输出最近的五个位置
        for (int i = 0; i < Math.min(count, locationDistances.size()); i++) {
            int index = locationDistances.get(i).getIndex();
            Store store = storeList.get(index);
            nearestStoreList.add(store);
        }

        return nearestStoreList;
    }

    private static double haversineDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径，单位为公里
        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c; // 返回距离，单位为公里
    }

    // 辅助类用于存储位置的索引和与目标点的距离
    static class LocationDistance {
        private int index;
        private double distance;

        public LocationDistance(int index, double distance) {
            this.index = index;
            this.distance = distance;
        }

        public int getIndex() {
            return index;
        }

        public double getDistance() {
            return distance;
        }
    }

    @Override
    public NearestOneStoreResponse getnearestOneStore(NearestRequest nearestRequest) {
        nearestRequest.setCount(1);
        List<Store> nearestStoreList = this.getNearestStore(nearestRequest);

        if (CollectionUtils.isEmpty(nearestStoreList)) {
            return null;
        }

        Store store = nearestStoreList.get(0);

        NearestOneStoreResponse nearestOneStoreResponse = new NearestOneStoreResponse();
        BeanUtils.copyProperties(store, nearestOneStoreResponse);

        //计算直线距离
        nearestOneStoreResponse.setLinearDistance(GeoUtils.haversine(nearestRequest.getLat(), nearestRequest.getLon(), store.getLat(), store.getLon()));

        return nearestOneStoreResponse;
    }
}

